-- drop function if exists sm_sc.fv_d_gemm_power2_dloss_dindepdt_1(float[], float[], int[]);
create or replace function sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
(
  i_dloss_ddepdt     float[]
, i_co_value         float[]
, i_indepdt_len      int[]    
)
returns float[]
as
$$
declare 
  v_dloss_ddepdt_ods_len         int[]   :=
    (
      select 
        array_agg(array_length(i_dloss_ddepdt, a_no) order by a_no) 
      from generate_series(1, array_ndims(i_dloss_ddepdt)) tb_a(a_no)
    )
  ;
  v_co_value_len             int[]   :=
    (
      select 
        array_agg(array_length(i_co_value, a_no) order by a_no) 
      from generate_series(1, array_ndims(i_co_value)) tb_a(a_no)
    )
  ;
  v_dloss_ddepdt_no_3opr_broadcast_len int[]   :=
    (
      select 
        array_agg(coalesce(greatest(i_indepdt_len[a_no_ng + array_length(i_indepdt_len, 1) + 1], v_co_value_len[a_no_ng + array_length(v_co_value_len, 1) + 1]), 1) order by a_no_ng)
        ||
        i_indepdt_len[array_length(i_indepdt_len, 1) - 1 : array_length(i_indepdt_len, 1) - 1]
        ||
        v_co_value_len[array_length(v_co_value_len, 1) : array_length(v_co_value_len, 1)]
      from generate_series(-greatest(array_length(i_indepdt_len, 1), array_length(v_co_value_len, 1), array_length(v_dloss_ddepdt_ods_len, 1)), -3) tb_a(a_no_ng)
    )
  ;
  v_dloss_ddepdt_broadcast             float[] ;
  v_indepdt_len                        int[]   :=
    array_fill(1, array[greatest(array_length(v_dloss_ddepdt_ods_len, 1) - array_length(i_indepdt_len, 1), 0)])
    || 
    i_indepdt_len
  ;
begin
  if v_dloss_ddepdt_ods_len <> v_dloss_ddepdt_no_3opr_broadcast_len
  then 
    v_dloss_ddepdt_broadcast :=
      sm_sc.fv_aggr_slice_sum_py
      (
        i_dloss_ddepdt
      , v_dloss_ddepdt_ods_len /` v_dloss_ddepdt_no_3opr_broadcast_len
      )
    ;
  else 
    v_dloss_ddepdt_broadcast := i_dloss_ddepdt;
  end if;
  
  -- return v_dloss_ddepdt_broadcast |**| (|^~| i_co_value);
  if array_ndims(v_dloss_ddepdt_broadcast) = 4
  then     
    if array_length(i_indepdt_len, 1) = 3
    then 
      return 
        sm_sc.fv_mx_slice_4d_2_3d_py
        (
          sm_sc.fv_aggr_slice_sum_py
          (
            v_dloss_ddepdt_broadcast |**| (|^~| sm_sc.fv_arr_to_power2(i_co_value))
          , v_dloss_ddepdt_no_3opr_broadcast_len[ : array_length(v_dloss_ddepdt_no_3opr_broadcast_len, 1) - 2] /` v_indepdt_len[ : array_length(v_indepdt_len, 1) - 2]
            ||
            array[1, 1]
          )
        , 1
        , 1
        )
      ;
    elsif array_length(i_indepdt_len, 1) = 2
    then
      return 
        sm_sc.fv_mx_slice_4d_2_2d_py
        (
          sm_sc.fv_aggr_slice_sum_py
          (
            v_dloss_ddepdt_broadcast |**| (|^~| sm_sc.fv_arr_to_power2(i_co_value))
          , v_dloss_ddepdt_no_3opr_broadcast_len[ : array_length(v_dloss_ddepdt_no_3opr_broadcast_len, 1) - 2] /` v_indepdt_len[ : array_length(v_indepdt_len, 1) - 2]
            ||
            array[1, 1]
          )
        , array[1, 2]
        , array[1, 1]
        )
      ;
    elsif array_length(i_indepdt_len, 1) = 4
    then
      return 
        sm_sc.fv_aggr_slice_sum_py
        (
          v_dloss_ddepdt_broadcast |**| (|^~| sm_sc.fv_arr_to_power2(i_co_value))
        , v_dloss_ddepdt_no_3opr_broadcast_len[ : array_length(v_dloss_ddepdt_no_3opr_broadcast_len, 1) - 2] /` v_indepdt_len[ : array_length(v_indepdt_len, 1) - 2]
          ||
          array[1, 1]
        )
      ;
    end if;
  elsif array_ndims(v_dloss_ddepdt_broadcast) = 3
  then 
    if array_length(i_indepdt_len, 1) = 2
    then 
      return 
        sm_sc.fv_mx_slice_3d_2_2d_py
        (
          sm_sc.fv_aggr_slice_sum_py
          (
            v_dloss_ddepdt_broadcast |**| (|^~| sm_sc.fv_arr_to_power2(i_co_value))
          , v_dloss_ddepdt_no_3opr_broadcast_len[ : array_length(v_dloss_ddepdt_no_3opr_broadcast_len, 1) - 2] /` v_indepdt_len[ : array_length(v_indepdt_len, 1) - 2]
            ||
            array[1, 1]
          )
        , 1
        , 1
        )
      ;
    elsif array_length(i_indepdt_len, 1) = 3
    then
      return 
        sm_sc.fv_aggr_slice_sum_py
        (
          v_dloss_ddepdt_broadcast |**| (|^~| sm_sc.fv_arr_to_power2(i_co_value))
        , v_dloss_ddepdt_no_3opr_broadcast_len[ : array_length(v_dloss_ddepdt_no_3opr_broadcast_len, 1) - 2] /` v_indepdt_len[ : array_length(v_indepdt_len, 1) - 2]
          ||
          array[1, 1]
        )
      ;
    end if;
  elsif array_ndims(v_dloss_ddepdt_broadcast) = 2
  then
    return 
      v_dloss_ddepdt_broadcast |**| (|^~| sm_sc.fv_arr_to_power2(i_co_value))
    ;
  end if;
end
$$
language plpgsql stable
parallel safe
cost 100;

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[2, 3]
--   )
--   )

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[5, 2, 3]
--   )
--   )

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[5, 3, 4])     ,
--     array[2, 3]
--   )
--   )

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[5, 6, 3, 4])     ,
--     array[2, 3]
--   )
--   )

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[5, 6, 2, 3]
--   )
--   )

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[5, 6, 3, 4])     ,
--     array[6, 2, 3]
--   )
--   )

-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[6, 3, 4])     ,
--     array[5, 6, 2, 3]
--   )
--   )

-- -- 
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[5, 6, 3, 4])     ,
--     array[5, 6, 2, 3]
--   ))
-- 
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[6, 2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[6, 3, 4])     ,
--     array[2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[6, 3, 4])     ,
--     array[1, 2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[6, 3, 4])     ,
--     array[6, 2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[5, 6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[1, 3, 4])     ,
--     array[6, 2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[6, 3, 4])     ,
--     array[2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[1, 3, 4])     ,
--     array[2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[1, 2, 3]
--   ))
--   
-- select array_dims(
--   sm_sc.fv_d_gemm_power2_dloss_dindepdt_1
--   (
--     sm_sc.fv_new_rand(array[6, 2, 4])     ,    -- dloss_ddepdt
--     sm_sc.fv_new_rand(array[3, 4])     ,
--     array[6, 2, 3]
--   ))